home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
program
/
vol16n13.zip
/
OPENTR.ZIP
/
OT_SRC.ZIP
/
OTVIEW.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1997-05-26
|
18KB
|
471 lines
// OTView.cpp : implementation of the COpenTrapView class
//
// OpenTrap Version 1.00 by Gregory A. Wolking
// Copyright ⌐ 1997 Ziff-Davis Publishing
// First published in PC Magazine, US Edition, July 1997.
#include "stdafx.h"
#include "OpenTrap.h"
#include "MainFrm.h"
#include "OTextern.h"
#include "OTDoc.h"
#include "OTView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// COpenTrapView
IMPLEMENT_DYNCREATE(COpenTrapView, CScrollView)
BEGIN_MESSAGE_MAP(COpenTrapView, CScrollView)
//{{AFX_MSG_MAP(COpenTrapView)
ON_WM_KEYDOWN()
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CScrollView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// COpenTrapView construction/destruction
COpenTrapView::COpenTrapView()
{
CWinApp* pApp = AfxGetApp();
CString buf1, buf2;
m_pFiltered_Recs = NULL;
m_intPage_Count = 0;
m_intCurrent_Page = 0;
m_fontCustom = NULL;
m_intLines_Per_Page = 1;
buf1 = pApp->GetProfileString(g_szFontKey, "Font Data", "***");
buf2 = pApp->GetProfileString(g_szFontKey, "Face", "***");
if ((buf1.Compare("***") != 0) && (buf2.Compare("***") != 0))
{
int args;
LOGFONT font;
args = sscanf(buf1, g_szFontFormat,
&font.lfHeight, &font.lfWidth, &font.lfEscapement,
&font.lfOrientation, &font.lfWeight, &font.lfItalic,
&font.lfUnderline, &font.lfStrikeOut, &font.lfCharSet,
&font.lfOutPrecision, &font.lfClipPrecision, &font.lfQuality,
&font.lfPitchAndFamily);
if (args == 13)
{
lstrcpy(font.lfFaceName, buf2);
m_fontCustom = new CFont;
if (!m_fontCustom->CreateFontIndirect(&font))
{
delete m_fontCustom;
m_fontCustom = NULL;
}
}
}
// Set default scroll sizes so initial WM_PAINT doesn't barf.
SetScrollSizes(MM_TEXT, CSize(100, 100));
}
COpenTrapView::~COpenTrapView()
{
if (m_pFiltered_Recs)
{
free(m_pFiltered_Recs);
m_pFiltered_Recs = NULL;
}
if (m_fontCustom) // If custom font is in use,
{
LOGFONT font; // Save font information to the Registry.
CString font_data;
m_fontCustom->GetLogFont(&font);
font_data.Format(g_szFontFormat,
font.lfHeight, font.lfWidth, font.lfEscapement,
font.lfOrientation, font.lfWeight, font.lfItalic,
font.lfUnderline, font.lfStrikeOut, font.lfCharSet,
font.lfOutPrecision, font.lfClipPrecision, font.lfQuality,
font.lfPitchAndFamily);
AfxGetApp()->WriteProfileString(g_szFontKey, "Font Data", font_data);
AfxGetApp()->WriteProfileString(g_szFontKey, "Face", font.lfFaceName);
delete m_fontCustom;
m_fontCustom = NULL;
}
else // Otherwise, delete font information from the Registry.
RegDeleteKey(HKEY_CURRENT_USER, "Software\\PC Magazine\\OpenTrap\\1.0\\View\\Font");
}
BOOL COpenTrapView::PreCreateWindow(CREATESTRUCT& cs)
{
return CScrollView::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// COpenTrapView drawing
void COpenTrapView::OnDraw(CDC* pDC)
{
CFont* old_font = NULL; // Pointer to save current font if needed.
COpenTrapDoc* pDoc = GetDocument(); // Get pointer to current document.
COLORREF clr_norm = GetSysColor(COLOR_WINDOW); // Background color for normal events
COLORREF clr_err = GetSysColor(COLOR_WINDOWTEXT); // Background color for error events
CRect my_rect;
CString text;
if (m_fontCustom) // If custom font is active,
old_font = pDC->SelectObject(m_fontCustom); // select it into the device context.
CSize text_size = pDC->GetTextExtent("M", 1); // Get size of an "em" in the current font.
int cur_y = 0;
if (!pDC->IsPrinting()) // If we're not printing,
{
if (g_bIsLogging || g_intRecCount == 0) // If logging or log is empty,
{
if (old_font)
pDC->SelectObject(old_font);
return; // nothing to draw.
}
if (m_intFilt_Rec_Count == 0) // If no records filtered,
{
text = "No matching records found."; // display appropriate message
pDC->TextOut(5, cur_y, text);
if (old_font)
pDC->SelectObject(old_font);
return; // and we're done.
}
// We have records to display, so get to it!
char outbuf[512];
CSize sizeTotal, sizePage, sizeLine;
CPoint scroll_pos = GetScrollPosition(); // Find where the scroll thumb is.
int view_top, view_bot, max_width = 0;
UINT cur_rec;
GetWindowRect(my_rect); // Get window coordinates.
my_rect.NormalizeRect();
// Determine the region we need to draw: from one full line above the
// window to one full line below it.
if (scroll_pos.y > text_size.cy)
view_top = (scroll_pos.y - text_size.cy) - (scroll_pos.y % text_size.cy);
else
view_top = 0;
view_bot = view_top + my_rect.Height() + text_size.cy * 2;
// Calculate which record is at the top of the drawing region.
cur_y = view_top;
cur_rec = (m_intCurrent_Page - 1) * m_intLines_Per_Page + (view_top / text_size.cy);
// Loop until we either reach the end of the viewport or run out of records.
while(cur_y < view_bot && cur_rec < m_intFilt_Rec_Count)
{
// Decode record to text buffer.
pDoc->Packed_to_ASCII(m_pFiltered_Recs[cur_rec].rec_num,
m_pFiltered_Recs[cur_rec].pRec, outbuf);
if (m_pFiltered_Recs[cur_rec].pRec->pr_error) // Set appropriate background color.
{
pDC->SetTextColor(clr_norm);
pDC->SetBkColor(clr_err);
}
else
{
pDC->SetBkColor(clr_norm);
pDC->SetTextColor(clr_err);
}
text_size = pDC->GetTextExtent(outbuf, strlen(outbuf) - 2); // Calculate size of text.
if (text_size.cx > max_width) // Update max width (used for setting horizontal scroll)
max_width = text_size.cx;
pDC->TextOut(5, cur_y, outbuf, strlen(outbuf) - 2); // Draw the text.
cur_y += text_size.cy; // Update position.
++cur_rec; // Next record.
}
// Calculate and set scroll sizes.
sizePage.cy = my_rect.Height() - (my_rect.Height() % text_size.cy);
sizeLine.cy = text_size.cy;
m_sizeCurrent_Page.cx = max_width + 10;
sizePage.cx = my_rect.Width();
sizeLine.cx = sizePage.cx / 10;
SetScrollSizes(MM_TEXT, m_sizeCurrent_Page, sizePage, sizeLine);
}
else // We're printing!
{
int line_y, left_margin, left_indent, targ_x, len;
UINT cur_rec;
CSize check_size;
CRect page_rect;
char outbuf[512], *p1, *p2;
BOOL new_page = FALSE, first_line;
// Set mapping mode. Note: in LOENGLISH mode, y decreases as we move down the page.
// This mode scales the font using logical units instead of pixels (as in MM_TEXT mode
// used for screen output) so the font is the same size regardless of printer resolution.
pDC->SetMapMode(MM_LOENGLISH);
// Get page rectangle in pixels.
page_rect = CRect(0, 0, pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
pDC->DPtoLP(page_rect); // Convert page rectangle to logical units.
text_size = pDC->GetTextExtent("M", 1); // Get size of an "em" in the current font.
line_y = text_size.cy; // Set height of one line.
page_rect.top -= (line_y * 2); // Top margin of two lines.
page_rect.bottom -= (line_y * 2); // Bottom margin of two lines.
clr_err = RGB(128, 128, 128); // Set error color to 50% gray.
clr_norm = RGB(255, 255, 255); // Normal color is white for printing.
pDC->SetTextColor(RGB(0, 0, 0)); // Text color for printing is black
pDC->SetBkColor(clr_norm); // on a white background.
left_margin = text_size.cx; // Set left margin of one em.
left_indent = text_size.cx * 3; // Left indent of 3 ems.
page_rect.right -= text_size.cx; // Right margin of 1 em.
// Now that we've got all of our dimensions calculated, draw records on the display context.
cur_y = page_rect.top; // Start at the top of the page.
for (cur_rec = 0; cur_rec < m_intFilt_Rec_Count; ++cur_rec)
{
if (new_page) // If flag is set,
{
cur_y = page_rect.top; // Back to top of page.
new_page = FALSE; // Clear flag.
Start_New_Page(pDC, old_font); // End current page and start a new page.
}
// Decode record to text buffer.
pDoc->Packed_to_ASCII(m_pFiltered_Recs[cur_rec].rec_num, m_pFiltered_Recs[cur_rec].pRec, outbuf);
// Set appropriate background color.
if (m_pFiltered_Recs[cur_rec].pRec->pr_error)
pDC->SetBkColor(clr_err);
else
pDC->SetBkColor(clr_norm);
// Calculate size of text, ignoring trailing CR/LF.
text_size = pDC->GetTextExtent(outbuf, strlen(outbuf) - 2);
p1 = outbuf;
first_line = TRUE;
// As long as text is too wide for one line,
while (text_size.cx + (first_line ? left_margin : left_indent) > page_rect.right)
{
p2 = p1 + strlen(p1) - 3; // Point to last character.
while (TRUE)
{ // Search backwards for either a space or a backslash.
while(*p2 != ' ' && *p2 != '\\' && p2 >= p1)
--p2;
// If we can't find a logical point at which to break the line,
if (p2 == p1)
{ // Resort to brute force -- get target line length.
targ_x = page_rect.right - (first_line ? left_margin : left_indent);
len = 1;
// Start with first character (p2 already points there).
// Loop until end of buffer is reached.
while (TRUE)
{ // Get width line up to current character.
check_size = pDC->GetTextExtent(p1, len);
if (check_size.cx < targ_x) // Does it fit?
++len; // add another character if so.
else
{ // otherwise back up to the last character that _did_ fit.
--len;
break;
}
}
p2 = p1 + len; // Point to end of text.
break; // Done adjusting.
}
// If logical break point found, get size of text up to that point.
check_size = pDC->GetTextExtent(p1, (p2 - p1) + 1);
if ((check_size.cx + (first_line ? left_margin : left_indent)) <= page_rect.right)
break; // Done adjusting if small enough.
else
--p2; // Otherwise, back up one character and keep looking.
}
// Draw the part of the text that fits.
pDC->TextOut((first_line ? left_margin : left_indent), cur_y, p1, (p2 - p1) + 1);
first_line = FALSE; // Clear first line flag.
cur_y -= line_y; // Update position.
if ((cur_y - line_y) < page_rect.bottom) // Room for another line?
{
cur_y = page_rect.top; // New page if not.
Start_New_Page(pDC, old_font);
}
p1 = p2 + 1; // Move past the text we just printed.
text_size = pDC->GetTextExtent(p1, strlen(p1) - 2); // Get size of remainder.
}
// Draw all text remaining after any adjustments.
pDC->TextOut((first_line ? left_margin : left_indent),
cur_y, p1, strlen(p1) - 2);
cur_y -= line_y; // Update page position.
new_page = ((cur_y - line_y) < page_rect.bottom); // Set flag if not enough room for another line.
}
}
if (old_font)
pDC->SelectObject(old_font);
}
void COpenTrapView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
}
/////////////////////////////////////////////////////////////////////////////
// COpenTrapView printing
BOOL COpenTrapView::OnPreparePrinting(CPrintInfo* pInfo)
{
// Disable the Print Dialog's "Page Number" and "Selection" radio buttons.
pInfo->m_pPD->m_pd.Flags |= (PD_NOPAGENUMS | PD_NOSELECTION);
return DoPreparePrinting(pInfo);
}
void COpenTrapView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}
void COpenTrapView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
/////////////////////////////////////////////////////////////////////////////
// COpenTrapView diagnostics
#ifdef _DEBUG
void COpenTrapView::AssertValid() const
{
CScrollView::AssertValid();
}
void COpenTrapView::Dump(CDumpContext& dc) const
{
CScrollView::Dump(dc);
}
COpenTrapDoc* COpenTrapView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(COpenTrapDoc)));
return (COpenTrapDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// COpenTrapView message handlers
// Called when document is updated.
// If lHint is non-zero, the "update" is simply
// the user selecting a different page, and lHint contains the
// identifier of the page command.
void COpenTrapView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
Calc_Scroll_Sizes((BOOL) lHint);
CScrollView::OnUpdate(pSender, lHint, pHint);
}
// Sets the parameters for the scroll bar.
// Called when document is updated.
// If update is an actual change to the document (e.g., log records added),
// the list of filtered records is rebuilt.
void COpenTrapView::Calc_Scroll_Sizes(BOOL page_change)
{
CSize size;
if (g_bIsLogging || g_intRecCount == 0)
{
size.cx = size.cy = 100;
SetScrollSizes(MM_TEXT, size);
return;
}
if (!page_change) // Did document actually change?
Build_Record_List(); // Rebuild record list if so.
CDC* pDC = GetDC(); // Get pointer to device context.
CFont* old_font = NULL;
if (m_fontCustom)
old_font = pDC->SelectObject(m_fontCustom);
size = pDC->GetTextExtent("M",1); // Get height of one line.
if (old_font) // Restore original font if necessary.
pDC->SelectObject(old_font);
m_intLines_Per_Page = 16384 / size.cy; // Get # of lines per page.
if (m_intLines_Per_Page > 1024) // Max is 1024 lines.
m_intLines_Per_Page = 1024;
// Get number of full pages.
m_intPage_Count = (m_intFilt_Rec_Count / m_intLines_Per_Page);
// Add one page if record count is not an even multiple of the line count.
if (m_intFilt_Rec_Count % m_intLines_Per_Page != 0)
++m_intPage_Count;
// Set vertical size of current page.
if (m_intFilt_Rec_Count > (m_intCurrent_Page * m_intLines_Per_Page)) // If current page is full,
size.cy = (size.cy * m_intLines_Per_Page); // Page height is max lines.
else // Otherwise,
size.cy = size.cy * (m_intFilt_Rec_Count % m_intLines_Per_Page); // Height is number of lines in the page.
m_sizeCurrent_Page = size;
SetScrollSizes(MM_TEXT, size);
// If scrolling to previous or last page,
// force scroll position to the bottom of the page.
if (page_change == ID_VIEW_PREVIOUS || page_change == ID_VIEW_LAST)
SetScrollPos(SB_VERT, size.cy, FALSE);
}
// Handles keyboard scrolling within the current page.
// Note that page navigation commands (Ctrl + key) are intercepted
// as accelerators, so they never appear as OnKeyDown events.
void COpenTrapView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
UINT msg = 0;
WPARAM func = 0;
switch (nChar) // Determine the scroll message and function.
{
case VK_DOWN: msg = WM_VSCROLL; func = SB_LINEDOWN; break;
case VK_UP: msg = WM_VSCROLL; func = SB_LINEUP; break;
case VK_NEXT: msg = WM_VSCROLL; func = SB_PAGEDOWN; break;
case VK_PRIOR: msg = WM_VSCROLL; func = SB_PAGEUP; break;
case VK_HOME: msg = WM_VSCROLL; func = SB_TOP; break;
case VK_END: msg = WM_VSCROLL; func = SB_BOTTOM; break;
case VK_LEFT: msg = WM_HSCROLL; func = SB_LINELEFT; break;
case VK_RIGHT: msg = WM_HSCROLL; func = SB_LINERIGHT;
}
if (msg) // If keystroke was a scroll command,
PostMessage(msg, func, NULL); // post the scroll message.
CScrollView::OnKeyDown(nChar, nRepCnt, nFlags);
}
// Builds array of pointers to filtered records and sets number
// of pages in the filtered view.
void COpenTrapView::Build_Record_List(void)
{
COpenTrapDoc * pDoc = GetDocument();
packed_record * pr = (packed_record*) g_pBufferStart;
UINT current = 0;
m_intFilt_Rec_Count = 0; // Reset filtered record count.
// Make sure array is big enough to hold entries for all records.
m_pFiltered_Recs = (filter_list *) realloc(m_pFiltered_Recs, g_intRecCount * sizeof(filter_list));
while (pr) // For each record:
{
++current; // Bump absolute record number.
if (pDoc->Filter_Record(pr)) // If record passes the filters,
{
m_pFiltered_Recs[m_intFilt_Rec_Count].pRec = pr; // add it to the array,
m_pFiltered_Recs[m_intFilt_Rec_Count].rec_num = current; // save absolute record number,
++m_intFilt_Rec_Count; // and update the count.
}
pr = pr->next_record; // Next record.
}
m_intPage_Count = m_intFilt_Rec_Count / m_intLines_Per_Page; // Set number of pages
if (m_intFilt_Rec_Count % m_intLines_Per_Page != 0) // Adjust if not an even multiple.
++m_intPage_Count;
m_intCurrent_Page = 1; // Set current page to 1.
// Release any memory not actually required for active array elements.
if (m_intFilt_Rec_Count)
m_pFiltered_Recs = (filter_list*) realloc(m_pFiltered_Recs, m_intFilt_Rec_Count * sizeof(filter_list));
else
{
free(m_pFiltered_Recs);
m_pFiltered_Recs = NULL;
}
}
// Called by OnDraw to end the current page and start a new one.
void COpenTrapView::Start_New_Page(CDC* pDC, CFont* old_font)
{
pDC->EndPage();
pDC->StartPage();
pDC->SetMapMode(MM_LOENGLISH);
if (m_fontCustom)
old_font = pDC->SelectObject(m_fontCustom);
}